<?php
/**
 * install.php
 * $Id$
 *
 * An interactive install script for OTPHP
 *
 * @link https://code.google.com/p/f2-otphp/
 * @package OTPHP
 *
 * @license http://www.gnu.org/licenses/lgpl-3.0-standalone.html
 * Please see the COPYING and COPYING.LESSER files in the doc/ directory or the url above for full copyright and license information.
 * @copyright Copyright 2013 F2 Developments, Inc.
 *
 * @author Robin Klingsberg <rklingsberg@f2dev.com>
 * @author $LastChangedBy$
 *
 * @version $Revision$
 */

echo <<<END

This script will install the OTPHP library.
This library requires that PHP has been compiled with the openssl library enabled,
and that openssl is installed on both the client and server systems.

See http://php.net/manual/en/openssl.installation.php for more information.

Press Enter to continue or Ctrl+C to cancel.

END;

fgets(STDIN);

/*** Obtain Settings ***/

echo <<<END
OK, let's get started!

Now, how paranoid do you want to be with file permissions?
This affects the server config files, database, and keys as well as all client files generated by this installation.
(Note: This has no effect on Windows installations)
\tA) None shall pass! (0600/0700) (default)
\tB) A little security can be a good thing. (0640/0750)
\tC) Whatevs, this is just a test install. (0644/0755)

END;
$s_Paranoia = trim(fgets(STDIN));

switch (strtolower($s_Paranoia))
{
	case 'b':
		$i_FileUMask = 0640;
		$i_DirUMask = 0750;
		break;
	case 'c':
		$i_FileUMask = 0644;
		$i_DirUMask = 0755;
		break;
	default:
		$i_FileUMask = 0600;
		$i_DirUMask = 0700;
		break;
}

echo "\nEnter path to installation [default: " .getcwd(). DIRECTORY_SEPARATOR .'OTPHP]: ';
$s_InstallPath = trim(fgets(STDIN));

if (empty($s_InstallPath))
{
	$s_InstallPath = '.' . DIRECTORY_SEPARATOR . 'OTPHP' . DIRECTORY_SEPARATOR;
}
elseif (DIRECTORY_SEPARATOR != substr($s_InstallPath, -1))
{
	$s_InstallPath .= DIRECTORY_SEPARATOR;
}

if ('.' != $s_InstallPath && !file_exists($s_InstallPath))
{
    echo "\nPath does not exist! Creating it...\n";
    if (!mkdir($s_InstallPath, true))
    {
	die("\n*** Creation of path failed! Please check the filesystem permissions and try again. ***\n");
    }
}

echo "\nEnter a password for the OTP server's database (or hit Enter to have a secure password generated and displayed on-screeen): ";
$s_ServerDBPassword = trim(fgets(STDIN));
if (empty($s_ServerDBPassword))
{
    $s_ServerDBPassword = sha1(openssl_random_pseudo_bytes(4096));
    echo "\nNew password: $s_ServerDBPassword";
    echo "\nPlease copy it to a secure location then hit Enter\n";
    fgets(STDIN);
}

echo "\nEnter the maximum number of authentication attempts permitted before lockout [min: 1, max: 20, default: 5]: ";
$i_MaxAuths = (int) trim(fgets(STDIN));

if (empty($i_MaxAuths))
{
	$i_MaxAuths = 5;
}
elseif ($i_MaxAuths < 1)
{
	$i_MaxAuths = 1;
}
elseif ($i_MaxAuths > 20)
{
	$i_MaxAuths = 20;
}

echo "\nEnter the number of HOTP iterations the server will check to ensure the client has not gotten ahead of it (look-ahead). [min: 0, max: 20, default: 5]: ";
$i_LookAhead = (int) trim(fgets(STDIN));

if (empty($i_LookAhead))
{
	$i_LookAhead = 5;
}
elseif ($i_LookAhead < 0)
{
	$i_LookAhead = 0;
}
elseif ($i_LookAhead > 20)
{
	$i_LookAhead = 20;
}

echo "\nEnter a length for the generated HOTP passwords [min: 6, max: 20, default: 10]: ";
$i_PasswordLength = (int) trim(fgets(STDIN));

if (empty($i_PasswordLength))
{
	$i_PasswordLength = 10;
}
elseif ($i_PasswordLength < 6)
{
	$i_PasswordLength = 6;
}
elseif ($i_PasswordLength > 20)
{
	$i_PasswordLength = 20;
}

echo "\nEnter a bit-length for the server's RSA key [default: 4096]: ";
$i_RSABits = (int) trim(fgets(STDIN));

if (empty($i_RSABits))
{
	$i_RSABits = 4096;
}

/*** Install ***/

echo "\nInstalling OTPHP...\n";

// Generate RSA keypair
$a_Settings = array(
    "private_key_type" => OPENSSL_KEYTYPE_RSA,
    "private_key_bits" => $i_RSABits
);
$r_PrivateKey = openssl_pkey_new($a_Settings);

if (false === $r_PrivateKey)
{
	die("\n*** Generation of server key failed! Ensure that there is a valid openssl.cnf in your system. See http://php.net/manual/en/openssl.installation.php for more information.***\n");
}

$a_PublicKeyDetails = openssl_pkey_get_details($r_PrivateKey);
$s_ServerPublicKey = $a_PublicKeyDetails["key"];

openssl_pkey_export($r_PrivateKey, $s_ServerPrivateKey);

// Write library files and set permissions
$s_ClientDataPath = $s_InstallPath.'client_data'.DIRECTORY_SEPARATOR;
$s_KeyPath = $s_InstallPath.'.keys'.DIRECTORY_SEPARATOR;

mkdir($s_ClientDataPath, 0700);
mkdir($s_KeyPath, $i_DirUMask);

copy('lib'.DIRECTORY_SEPARATOR.'OTPClient.php', $s_ClientDataPath.'OTPClient.php');
chmod($s_ClientDataPath.'OTPClient.php', 0755);

copy('lib'.DIRECTORY_SEPARATOR.'ClientEntity.php', $s_ClientDataPath.'ClientEntity.php');
chmod($s_ClientDataPath.'ClientEntity.php', 0755);

copy('lib'.DIRECTORY_SEPARATOR.'OTPServer.php', $s_InstallPath.'OTPServer.php');
chmod($s_InstallPath.'OTPServer.php', 0755);

file_put_contents($s_KeyPath.'server.pub', $s_ServerPublicKey);
chmod($s_KeyPath.'server.pub', $i_FileUMask);
file_put_contents($s_KeyPath.'server.key', $s_ServerPrivateKey);
chmod($s_KeyPath.'server.key', $i_FileUMask);

// Create server database
$o_DB = new PDO('sqlite:'.$s_InstallPath.'server.db');

$o_DB->exec('CREATE TABLE IF NOT EXISTS clients
		(
			id TEXT PRIMARY KEY,
			server_public_key TEXT,
			counter INTEGER,
			key TEXT,
			password_length INTEGER,
			status INTEGER,
			failed_auths INTEGER DEFAULT 0,
			init_vector TEXT
		)
	    ');

chmod($s_InstallPath.'server.db', $i_FileUMask);

// Write variables into the server configuration file
$o_Config = new SimpleXMLElement('<otpserver></otpserver>');
$o_Config->addChild('public_key_path', '.keys' . DIRECTORY_SEPARATOR . 'server.pub');
$o_Config->addChild('private_key_path', '.keys' . DIRECTORY_SEPARATOR . 'server.key');
$o_Config->addChild('db_path', 'server.db');
$o_Config->addChild('db_key', $s_ServerDBPassword);
$o_Config->addChild('client_export_path', 'client_data'.DIRECTORY_SEPARATOR);
$o_Config->addChild('max_auths', $i_MaxAuths);
$o_Config->addChild('look_ahead', $i_LookAhead);
$o_Config->addChild('password_length', $i_PasswordLength);
$o_Config->addChild('file_umask', $i_FileUMask);
$o_Config->addChild('dir_umask', $i_DirUMask);

file_put_contents($s_InstallPath.'config.xml', $o_Config->asXML());
chmod($s_InstallPath.'config.xml', $i_FileUMask);

echo "\nInstall finished!\n";
echo "\nFor usage guidelines please read the documentation inside the 'doc' folder.\n";
?>
